﻿#region MIT Licence
/*
 * Copyright (C) 2014 PdfCreative
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
 * and associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom 
 * the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#endregion

using System;
using System.Collections.Generic;
using System.Text;

namespace PdfCreative.Pdf.Graphics
{
    /// <summary>
    /// The Rgb class is a static convenience class that contains ready-made pens, brushes and colours that
    /// use the RGB colour space.
    /// </summary>
    public static class Rgb
    {
        // Private fields
        // ==============
        #region Private fields
        private static SolidBrush[] _brushes;
        private static RgbColour[] _colours;
        private static Pen[] _pens;
        #endregion



        // Public properties
        // =================
        #region Colours
        /// <summary>
        /// Retrieves a bright red colour.
        /// </summary>
        public static RgbColour Red { get { return _colours[(int)ColourCode.Red]; } }

        /// <summary>
        /// Retrieves a bright green colour.
        /// </summary>
        public static RgbColour Green { get { return _colours[(int)ColourCode.Green]; } }

        /// <summary>
        /// Retrieves a bright yellow colour.
        /// </summary>
        public static RgbColour Yellow { get { return _colours[(int)ColourCode.Yellow]; } }

        /// <summary>
        /// Retrieves a bright blue colour.
        /// </summary>
        public static RgbColour Blue { get { return _colours[(int)ColourCode.Blue]; } }

        /// <summary>
        /// Retrieves a bright magenta colour.
        /// </summary>
        public static RgbColour Magenta { get { return _colours[(int)ColourCode.Magenta]; } }

        /// <summary>
        /// Retrieves a bright cyan colour.
        /// </summary>
        public static RgbColour Cyan { get { return _colours[(int)ColourCode.Cyan]; } }

        /// <summary>
        /// Retrieves a white colour.
        /// </summary>
        public static RgbColour White { get { return _colours[(int)ColourCode.White]; } }

        /// <summary>
        /// Retrieves a white colour.
        /// </summary>
        public static RgbColour Black { get { return _colours[(int)ColourCode.Black]; } }

        /// <summary>
        /// Retrieves a dark red colour.
        /// </summary>
        public static RgbColour DarkRed { get { return _colours[(int)ColourCode.DarkRed]; } }

        /// <summary>
        /// Retrieves a dark green colour.
        /// </summary>
        public static RgbColour DarkGreen { get { return _colours[(int)ColourCode.DarkGreen]; } }

        /// <summary>
        /// Retrieves a dark yellow colour.
        /// </summary>
        public static RgbColour DarkYellow { get { return _colours[(int)ColourCode.DarkYellow]; } }

        /// <summary>
        /// Retrieves a dark blue colour.
        /// </summary>
        public static RgbColour DarkBlue { get { return _colours[(int)ColourCode.DarkBlue]; } }

        /// <summary>
        /// Retrieves a dark magenta colour.
        /// </summary>
        public static RgbColour DarkMagenta { get { return _colours[(int)ColourCode.DarkMagenta]; } }

        /// <summary>
        /// Retrieves a dark cyan colour.
        /// </summary>
        public static RgbColour DarkCyan { get { return _colours[(int)ColourCode.DarkCyan]; } }

        /// <summary>
        /// Retrieves a grey colour that is 90% white, 10% black.
        /// </summary>
        public static RgbColour Grey90 { get { return _colours[(int)ColourCode.Grey90]; } }

        /// <summary>
        /// Retrieves a grey colour that is 80% white, 20% black.
        /// </summary>
        public static RgbColour Grey80 { get { return _colours[(int)ColourCode.Grey80]; } }

        /// <summary>
        /// Retrieves a grey colour that is 70% white, 30% black.
        /// </summary>
        public static RgbColour Grey70 { get { return _colours[(int)ColourCode.Grey70]; } }

        /// <summary>
        /// Retrieves a grey colour that is 60% white, 40% black.
        /// </summary>
        public static RgbColour Grey60 { get { return _colours[(int)ColourCode.Grey60]; } }

        /// <summary>
        /// Retrieves a grey colour that is half white, half black.
        /// </summary>
        public static RgbColour Grey50 { get { return _colours[(int)ColourCode.Grey50]; } }

        /// <summary>
        /// Retrieves a grey colour that is 40% white, 60% black.
        /// </summary>
        public static RgbColour Grey40 { get { return _colours[(int)ColourCode.Grey40]; } }

        /// <summary>
        /// Retrieves a grey colour that is 30% white, 70% black.
        /// </summary>
        public static RgbColour Grey30 { get { return _colours[(int)ColourCode.Grey30]; } }

        /// <summary>
        /// Retrieves a grey colour that is 20% white, 80% black.
        /// </summary>
        public static RgbColour Grey20 { get { return _colours[(int)ColourCode.Grey20]; } }

        /// <summary>
        /// Retrieves a grey colour that is 10% white, 90% black.
        /// </summary>
        public static RgbColour Grey10 { get { return _colours[(int)ColourCode.Grey10]; } }
        #endregion

        #region Pens
        /// <summary>
        /// Retrieves a bright red pen.
        /// </summary>
        public static Pen RedPen { get { return _pens[(int)ColourCode.Red]; } }

        /// <summary>
        /// Retrieves a bright green pen.
        /// </summary>
        public static Pen GreenPen { get { return _pens[(int)ColourCode.Green]; } }

        /// <summary>
        /// Retrieves a bright yellow pen.
        /// </summary>
        public static Pen YellowPen { get { return _pens[(int)ColourCode.Yellow]; } }

        /// <summary>
        /// Retrieves a bright blue pen.
        /// </summary>
        public static Pen BluePen { get { return _pens[(int)ColourCode.Blue]; } }

        /// <summary>
        /// Retrieves a bright magenta pen.
        /// </summary>
        public static Pen MagentaPen { get { return _pens[(int)ColourCode.Magenta]; } }

        /// <summary>
        /// Retrieves a bright cyan pen.
        /// </summary>
        public static Pen CyanPen { get { return _pens[(int)ColourCode.Cyan]; } }

        /// <summary>
        /// Retrieves a white pen.
        /// </summary>
        public static Pen WhitePen { get { return _pens[(int)ColourCode.White]; } }

        /// <summary>
        /// Retrieves a white pen.
        /// </summary>
        public static Pen BlackPen { get { return _pens[(int)ColourCode.Black]; } }

        /// <summary>
        /// Retrieves a dark red pen.
        /// </summary>
        public static Pen DarkRedPen { get { return _pens[(int)ColourCode.DarkRed]; } }

        /// <summary>
        /// Retrieves a dark green pen.
        /// </summary>
        public static Pen DarkGreenPen { get { return _pens[(int)ColourCode.DarkGreen]; } }

        /// <summary>
        /// Retrieves a dark yellow pen.
        /// </summary>
        public static Pen DarkYellowPen { get { return _pens[(int)ColourCode.DarkYellow]; } }

        /// <summary>
        /// Retrieves a dark blue pen.
        /// </summary>
        public static Pen DarkBluePen { get { return _pens[(int)ColourCode.DarkBlue]; } }

        /// <summary>
        /// Retrieves a dark magenta pen.
        /// </summary>
        public static Pen DarkMagentaPen { get { return _pens[(int)ColourCode.DarkMagenta]; } }

        /// <summary>
        /// Retrieves a dark cyan pen.
        /// </summary>
        public static Pen DarkCyanPen { get { return _pens[(int)ColourCode.DarkCyan]; } }

        /// <summary>
        /// Retrieves a grey pen that is 90% white, 10% black.
        /// </summary>
        public static Pen Grey90Pen { get { return _pens[(int)ColourCode.Grey90]; } }

        /// <summary>
        /// Retrieves a grey pen that is 80% white, 20% black.
        /// </summary>
        public static Pen Grey80Pen { get { return _pens[(int)ColourCode.Grey80]; } }

        /// <summary>
        /// Retrieves a grey pen that is 70% white, 30% black.
        /// </summary>
        public static Pen Grey70Pen { get { return _pens[(int)ColourCode.Grey70]; } }

        /// <summary>
        /// Retrieves a grey pen that is 60% white, 40% black.
        /// </summary>
        public static Pen Grey60Pen { get { return _pens[(int)ColourCode.Grey60]; } }

        /// <summary>
        /// Retrieves a grey pen that is half white, half black.
        /// </summary>
        public static Pen Grey50Pen { get { return _pens[(int)ColourCode.Grey50]; } }

        /// <summary>
        /// Retrieves a grey pen that is 40% white, 60% black.
        /// </summary>
        public static Pen Grey40Pen { get { return _pens[(int)ColourCode.Grey40]; } }

        /// <summary>
        /// Retrieves a grey pen that is 30% white, 70% black.
        /// </summary>
        public static Pen Grey30Pen { get { return _pens[(int)ColourCode.Grey30]; } }

        /// <summary>
        /// Retrieves a grey pen that is 20% white, 80% black.
        /// </summary>
        public static Pen Grey20Pen { get { return _pens[(int)ColourCode.Grey20]; } }

        /// <summary>
        /// Retrieves a grey pen that is 10% white, 90% black.
        /// </summary>
        public static Pen Grey10Pen { get { return _pens[(int)ColourCode.Grey10]; } }
        #endregion

        #region Brushes
        /// <summary>
        /// Retrieves a bright red brush.
        /// </summary>
        public static SolidBrush RedBrush { get { return _brushes[(int)ColourCode.Red]; } }

        /// <summary>
        /// Retrieves a bright green brush.
        /// </summary>
        public static SolidBrush GreenBrush { get { return _brushes[(int)ColourCode.Green]; } }

        /// <summary>
        /// Retrieves a bright yellow brush.
        /// </summary>
        public static SolidBrush YellowBrush { get { return _brushes[(int)ColourCode.Yellow]; } }

        /// <summary>
        /// Retrieves a bright blue brush.
        /// </summary>
        public static SolidBrush BlueBrush { get { return _brushes[(int)ColourCode.Blue]; } }

        /// <summary>
        /// Retrieves a bright magenta brush.
        /// </summary>
        public static SolidBrush MagentaBrush { get { return _brushes[(int)ColourCode.Magenta]; } }

        /// <summary>
        /// Retrieves a bright cyan brush.
        /// </summary>
        public static SolidBrush CyanBrush { get { return _brushes[(int)ColourCode.Cyan]; } }

        /// <summary>
        /// Retrieves a white brush.
        /// </summary>
        public static SolidBrush WhiteBrush { get { return _brushes[(int)ColourCode.White]; } }

        /// <summary>
        /// Retrieves a white brush.
        /// </summary>
        public static SolidBrush BlackBrush { get { return _brushes[(int)ColourCode.Black]; } }

        /// <summary>
        /// Retrieves a dark red brush.
        /// </summary>
        public static SolidBrush DarkRedBrush { get { return _brushes[(int)ColourCode.DarkRed]; } }

        /// <summary>
        /// Retrieves a dark green brush.
        /// </summary>
        public static SolidBrush DarkGreenBrush { get { return _brushes[(int)ColourCode.DarkGreen]; } }

        /// <summary>
        /// Retrieves a dark yellow brush.
        /// </summary>
        public static SolidBrush DarkYellowBrush { get { return _brushes[(int)ColourCode.DarkYellow]; } }

        /// <summary>
        /// Retrieves a dark blue brush.
        /// </summary>
        public static SolidBrush DarkBlueBrush { get { return _brushes[(int)ColourCode.DarkBlue]; } }

        /// <summary>
        /// Retrieves a dark magenta brush.
        /// </summary>
        public static SolidBrush DarkMagentaBrush { get { return _brushes[(int)ColourCode.DarkMagenta]; } }

        /// <summary>
        /// Retrieves a dark cyan brush.
        /// </summary>
        public static SolidBrush DarkCyanBrush { get { return _brushes[(int)ColourCode.DarkCyan]; } }

        /// <summary>
        /// Retrieves a grey brush that is 90% white, 10% black.
        /// </summary>
        public static SolidBrush Grey90Brush { get { return _brushes[(int)ColourCode.Grey90]; } }

        /// <summary>
        /// Retrieves a grey brush that is 80% white, 20% black.
        /// </summary>
        public static SolidBrush Grey80Brush { get { return _brushes[(int)ColourCode.Grey80]; } }

        /// <summary>
        /// Retrieves a grey brush that is 70% white, 30% black.
        /// </summary>
        public static SolidBrush Grey70Brush { get { return _brushes[(int)ColourCode.Grey70]; } }

        /// <summary>
        /// Retrieves a grey brush that is 60% white, 40% black.
        /// </summary>
        public static SolidBrush Grey60Brush { get { return _brushes[(int)ColourCode.Grey60]; } }

        /// <summary>
        /// Retrieves a grey brush that is half white, half black.
        /// </summary>
        public static SolidBrush Grey50Brush { get { return _brushes[(int)ColourCode.Grey50]; } }

        /// <summary>
        /// Retrieves a grey brush that is 40% white, 60% black.
        /// </summary>
        public static SolidBrush Grey40Brush { get { return _brushes[(int)ColourCode.Grey40]; } }

        /// <summary>
        /// Retrieves a grey brush that is 30% white, 70% black.
        /// </summary>
        public static SolidBrush Grey30Brush { get { return _brushes[(int)ColourCode.Grey30]; } }

        /// <summary>
        /// Retrieves a grey brush that is 20% white, 80% black.
        /// </summary>
        public static SolidBrush Grey20Brush { get { return _brushes[(int)ColourCode.Grey20]; } }

        /// <summary>
        /// Retrieves a grey brush that is 10% white, 90% black.
        /// </summary>
        public static SolidBrush Grey10Brush { get { return _brushes[(int)ColourCode.Grey10]; } }
        #endregion



        // Private implementation
        // ======================
        #region Private implementation
        /// <summary>
        /// Retrieves the colour specification of a colour code. The colour specification is represented
        /// by the RgbColour attribute that decorates the fields of the ColourCode enumeration.
        /// </summary>
        /// <param name="colourCode">The colour code.</param>
        /// <returns>The colour specification.</returns>
        private static RgbColourAttribute GetColourSpecification(ColourCode colourCode)
        {
            RgbColourAttribute result = null;

            System.Reflection.FieldInfo fieldInfo = colourCode.GetType().GetField(colourCode.ToString());
            foreach (RgbColourAttribute attr in fieldInfo.GetCustomAttributes(typeof(RgbColourAttribute), true))
            {
                result = attr; break;
            }

            return result;
        }

        /// <summary>
        /// Sets up the stock objects that can be retrieved from the Rgb class.
        /// </summary>
        private static void SetupStockObjects()
        {
            int count = Enum.GetValues(typeof(ColourCode)).Length;

            _colours = new RgbColour[count];
            _pens = new Pen[count];
            _brushes = new SolidBrush[count];

            for (int colour = 0; colour < count; colour++)
            {
                // Retrieve the colour specification for this colour.
                RgbColourAttribute colourSpec = GetColourSpecification((ColourCode)colour);

                // Create the colour, and a pen and brush that match it.
                _colours[colour] = new RgbColour(colourSpec.Red, colourSpec.Green, colourSpec.Blue);
                _pens[colour] = new Pen(_colours[colour], 0.25f);
                _brushes[colour] = new SolidBrush(_colours[colour]);
            }
        }
        #endregion



        // Private constructor
        // ===================
        #region Public constructor
        /// <summary>
        /// Sets up the Rgb static class.
        /// </summary>
        static Rgb()
        {
            SetupStockObjects();
        }
        #endregion



        // Private types
        // =============
        #region ColourCode enumeration
        /// <summary>
        /// The ColourCode enumeration lists the colours of the stock objects that can be retrieved from the
        /// Rgb class.
        /// </summary>
        private enum ColourCode
        {
            [RgbColour(Red=0, Green=0, Blue=0)]
            Black,

            [RgbColour(Red=255, Green=0, Blue=0)]
            Red,

            [RgbColour(Red = 0, Green = 255, Blue = 0)]
            Green,

            [RgbColour(Red = 255, Green = 255, Blue = 0)]
            Yellow,

            [RgbColour(Red = 0, Green = 0, Blue = 255)]
            Blue,

            [RgbColour(Red = 255, Green = 0, Blue = 255)]
            Magenta,

            [RgbColour(Red = 0, Green = 255, Blue = 255)]
            Cyan,

            [RgbColour(Red = 255, Green = 255, Blue = 255)]
            White,

            [RgbColour(Red = 127, Green = 0, Blue = 0)]
            DarkRed,

            [RgbColour(Red = 0, Green = 127, Blue = 0)]
            DarkGreen,

            [RgbColour(Red = 127, Green = 127, Blue = 0)]
            DarkYellow,

            [RgbColour(Red = 0, Green = 0, Blue = 127)]
            DarkBlue,

            [RgbColour(Red = 127, Green = 0, Blue = 127)]
            DarkMagenta,

            [RgbColour(Red = 0, Green = 127, Blue = 127)]
            DarkCyan,

            [RgbColour(Red = 229, Green = 229, Blue = 229)]
            Grey90,

            [RgbColour(Red = 204, Green = 204, Blue = 204)]
            Grey80,

            [RgbColour(Red = 178, Green = 178, Blue = 178)]
            Grey70,

            [RgbColour(Red = 153, Green = 153, Blue = 153)]
            Grey60,

            [RgbColour(Red = 127, Green = 127, Blue = 127)]
            Grey50,

            [RgbColour(Red = 102, Green = 102, Blue = 102)]
            Grey40,

            [RgbColour(Red = 76, Green = 76, Blue = 76)]
            Grey30,

            [RgbColour(Red = 51, Green = 51, Blue = 51)]
            Grey20,

            [RgbColour(Red = 25, Green = 25, Blue = 25)]
            Grey10
        }
        #endregion

        #region RgbColourAttribute class
        /// <summary>
        /// The RgbColourAttribute class represent the RgbColour attribute that is used to decorate fields
        /// of the ColourCode enumeration. It links a ColourCode field to a colour expressed in the RGB
        /// colour space.
        /// </summary>
        [AttributeUsage(AttributeTargets.Field)]
        private class RgbColourAttribute : Attribute
        {
            // Private fields
            // ==============
            #region Private fields
            private byte _red;
            private byte _green;
            private byte _blue;
            #endregion



            // Public properties
            // =================
            #region Public properties
            /// <summary>
            /// Sets or retrieves the blue component of the colour.
            /// </summary>
            public byte Blue
            {
                get { return _blue; }
                set { _blue = value; }
            }

            /// <summary>
            /// Sets or retrieves the green component of the colour.
            /// </summary>
            public byte Green
            {
                get { return _green; }
                set { _green = value; }
            }

            /// <summary>
            /// Sets or retrieves the red component of the colour.
            /// </summary>
            public byte Red
            {
                get { return _red; }
                set { _red = value; }
            }
            #endregion

        } // RgbColourAttribute class
        #endregion

    } // Rgb class
}
